package com.leo.base.utils;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageConfig;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Hashtable;

/**
 * @ClassName QRCodeGeneratorUtils
 * @Description 二维码生成工具类
 * @Author wangss
 * @date 2020.11.18 18:02
 * @Version 1.0
 */
public class QrcodeGeneratorUtils {

    private static final MatrixToLogoImageConfig DEFAULT_CONFIG = new MatrixToLogoImageConfig();

    /**
     * 根据文本内容生成二维码数据
     *
     * @param contents 文本
     * @param width    宽
     * @param height   高
     * @return
     */
    public static BitMatrix generateQRCode(String contents, int width, int height) throws WriterException {

        Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>();
        // 设置字符编码
        hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
        // 指定纠错等级
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
        // 设置边框
        hints.put(EncodeHintType.MARGIN, "0");

        QRCodeWriter qrCodeWriter = new QRCodeWriter();
        return qrCodeWriter.encode(contents, BarcodeFormat.QR_CODE, width, height, hints);
    }

    /**
     * 生成纯文本二维码图片
     *
     * @param contents      文本内容
     * @param width         宽
     * @param height        高
     * @param format        格式
     * @param saveImagePath 图片保存路径(绝对路径)
     * @throws Exception
     */
    public static void writeToPath(String contents, int width, int height, String format, String saveImagePath) throws Exception {
        QrcodeGeneratorUtils.writeToPath(generateQRCode(contents, width, height), format, saveImagePath, null);
    }

    /**
     * 写入二维码图片，并将logo写入二维码中
     *
     * @param bitMatrix     要写入的二维码
     * @param format        二维码照片格式
     * @param saveImagePath 二维码照片保存路径(绝对路径)
     * @param logoPath      logo路径(绝对路径)
     * @throws IOException
     */
    public static void writeToPath(BitMatrix bitMatrix, String format, String saveImagePath, String logoPath) throws Exception {
        QrcodeGeneratorUtils.writeToPath(bitMatrix, format, saveImagePath, logoPath, DEFAULT_CONFIG);
    }

    /**
     * 写入二维码、以及将照片logo写入二维码中
     *
     * @param matrix     要写入的二维码
     * @param format     二维码照片格式
     * @param imagePath  二维码照片保存路径(绝对路径)
     * @param logoPath   logo路径(绝对路径)
     * @param logoConfig logo配置对象
     * @throws IOException
     */
    public static void writeToPath(BitMatrix matrix, String format, String imagePath, String logoPath, MatrixToLogoImageConfig logoConfig) throws Exception {
        // 文件保存位置
        Path file = Paths.get(imagePath);
        MatrixToImageWriter.writeToPath(matrix, format, file, new MatrixToImageConfig());

        if (null != logoPath && !"".equals(logoPath)) {
            //添加logo图片, 此处一定需要重新进行读取，而不能直接使用二维码的BufferedImage 对象
            BufferedImage img = ImageIO.read(new File(imagePath));
            QrcodeGeneratorUtils.overlapImage(img, logoPath, logoConfig);
            //写入logo照片到二维码
            ImageIO.write(img, format, new File(imagePath));

        }
    }

    /**
     * 将照片logo添加到二维码中间
     *
     * @param image    生成的二维码照片对象
     * @param logoPath logo照片路径(绝对路径)
     */
    private static void overlapImage(BufferedImage image, String logoPath, MatrixToLogoImageConfig logoConfig) throws Exception {
        BufferedImage logo = ImageIO.read(new File(logoPath));
        Graphics2D g = image.createGraphics();
        //考虑到logo照片贴到二维码中，建议大小不要超过二维码的1/5;
        int width = image.getWidth() / logoConfig.getLogoPart();
        int height = image.getHeight() / logoConfig.getLogoPart();
        //logo起始位置，此目的是为logo居中显示
        int x = (image.getWidth() - width) / 2;
        int y = (image.getHeight() - height) / 2;
        //绘制图
        g.drawImage(logo, x, y, width, height, null);

        //给logo画边框
        //构造一个具有指定线条宽度以及 cap 和 join 风格的默认值的实心 BasicStroke
        g.setStroke(new BasicStroke(logoConfig.getBorder()));
        g.setColor(logoConfig.getBorderColor());
        g.drawRect(x, y, width, height);

        g.dispose();
    }

    /**
     * 生成纯文本二维码图片(awt)
     *
     * @param contents
     * @param width
     * @param height
     * @return
     * @throws WriterException
     */
    public static BufferedImage generatorQRCodeImage(String contents, int width, int height) throws WriterException {
        return MatrixToImageWriter.toBufferedImage(QrcodeGeneratorUtils.generateQRCode(contents, width, height));
    }

    /**
     * 生成纯文本二维码图片(javafx)
     *
     * @param contents
     * @param width
     * @param height
     * @return
     * @throws WriterException
     */
    public static ImageView generatorQRCodeImageFx(String contents, int width, int height) throws WriterException {
        WritableImage writableImage = SwingFXUtils.toFXImage(QrcodeGeneratorUtils.generatorQRCodeImage(contents, width, height), null);
        return new ImageView(writableImage);
    }

    /**
     * 生成纯文本二维码图片(javafx)
     *
     * @param contents
     * @param width
     * @param height
     * @param logoPath logo照片路径(绝对路径)
     * @return
     * @throws WriterException
     */
    public static ImageView generatorQRCodeImageFx(String contents, int width, int height, String logoPath) throws Exception {
        BufferedImage bufferedImage = QrcodeGeneratorUtils.generatorQRCodeImage(contents, width, height);
        QrcodeGeneratorUtils.overlapImage(bufferedImage, logoPath, DEFAULT_CONFIG);
        WritableImage writableImage = SwingFXUtils.toFXImage(bufferedImage, null);
        return new ImageView(writableImage);
    }


    public static void main(String[] args) {
        try {
//            generateQRCodeImage("This is my first QR Code", 350, 350, "D:\\work\\idea-workspace\\leo-javafx-parent\\leo-084-javafx-zxing\\src\\main\\resources\\images\\touxiang.png");

            writeToPath(generateQRCode("王算算", 350, 350), "png", "D:\\work\\idea-workspace\\leo-javafx-parent\\leo-084-javafx-zxing\\src\\main\\resources\\images\\1.png", "D:\\work\\idea-workspace\\leo-javafx-parent\\leo-084-javafx-zxing\\src\\main\\resources\\images\\touxiang.png");
//            writeToPath("王算算", 350, 350, "png", "D:\\work\\idea-workspace\\leo-javafx-parent\\leo-084-javafx-zxing\\src\\main\\resources\\images\\1.png");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
